import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class Part2 {
	
	private JFrame frame;
	enum Axes { X, Y, Z };
	private class Animation {
		Polygon p;
		int numFrames;
		int numRotations;
		Axes axisOfRotation;
		
		public Animation( Polygon p, int numFrames, int numRotations, Axes axisOfRotation) {
			this.p = p;
			this.numFrames = numFrames;
			this.numRotations = numRotations;
			this.axisOfRotation = axisOfRotation;
		}
		
		public void draw(BufferedImage b, int frame) {
			//BufferedImage b = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			//Graphics2D g = b.createGraphics();
			
			double rotation = (double)numRotations / numFrames  * 360 * frame;
			switch(axisOfRotation) {
			case X:
				p.xAxisTheta = Math.toRadians(rotation);
				break;
			case Y:
				p.yAxisTheta = Math.toRadians(rotation);
				break;
			case Z:
				p.zAxisTheta = Math.toRadians(rotation);
				break;
			}
			
			p.drawTo(b);
		}
	}
	
	private class Vertex {
		double x, y, z;
		
		public Vertex(double x, double y, double z) {
			this.x = x;
			this.y = y;
			this.z = z;
		}
		
		public Vertex(double x, double y) {
			this(x, y, 0);
		}
		
		public Vertex rotate(double xTheta, double yTheta, double zTheta) {
			return this.rotateAboutX(xTheta).rotateAboutY(yTheta).rotateAboutZ(zTheta);
		}
		
		public Vertex rotateAboutX(double theta) {
			double[][] rotationMatrix = {
					{1, 0, 0},
					{0, Math.cos(theta), -Math.sin(theta)},
					{0, Math.sin(theta), Math.cos(theta)}
			};
			
			return rotate(rotationMatrix);
		}
		
		public Vertex rotateAboutY(double theta) {
			double[][] rotationMatrix = {
					{Math.cos(theta), 0, Math.sin(theta)},
					{0, 1, 0},
					{-Math.sin(theta), 0, Math.cos(theta)}
			};
			
			return rotate(rotationMatrix);
		}
		
		public Vertex rotateAboutZ(double theta) {
			double[][] rotationMatrix = {
					{Math.cos(theta), -Math.sin(theta), 0},
					{Math.sin(theta), Math.cos(theta), 0},
					{0, 0, 1}
			};
			
			return rotate(rotationMatrix);
		}
		
		public Vertex rotate(double[][] rotationMatrix) {
			
			double[][] vertexMatrix = {
					{x},
					{y},
					{z}
			};
			
			double[][] rotated = Part1.multiply(rotationMatrix, vertexMatrix);
			
			return new Vertex(rotated[0][0], rotated[1][0], rotated[2][0]);
		}
		
		public double[][] getMatrix() {
			return new double[][] {
					{x},
					{y},
					{z}
			};
		}
	}
	
	private class Polygon {
		List<Vertex> vertices;
		double xAxisTheta, yAxisTheta, zAxisTheta;
		int centerX, centerY;
		
		/*public Polygon() {
			this.vertices = new ArrayList<Vertex>();
		}*/
		
		public Polygon(int centerX, int centerY, Vertex... vertices) {
			this.vertices = new ArrayList<Vertex>();
			
			double maxX = 0, maxY = 0;
			for (Vertex v : vertices) {
				if (v.x > maxX)
					maxX = v.x;
				if (v.y > maxY)
					maxY = v.y;
			}
			for (Vertex v : vertices) {
				v.x -= maxX/2;
				v.y -= maxY/2;
				this.vertices.add(v);
			}
			
			xAxisTheta = 0;
			yAxisTheta = 0;
			zAxisTheta = 0;
			this.centerX = centerX;
			this.centerY = centerY;
		}
		
		public void addVertex(double x, double y) {
			addVertex(x, y, 0);
		}
		
		public void addVertex(double x, double y, double z) {
			vertices.add(new Vertex(x, y, z));
		}
		
		public void drawLine(BufferedImage b, int x1, int y1, int x2, int y2) {
			Graphics2D g = b.createGraphics();
			g.setColor(Color.black);
			
			int centerX = b.getWidth() / 2 + this.centerX;
			int centerY = b.getHeight() / 2 - this.centerY;
			
			g.drawLine(centerX + x1, centerY - y1, centerX + x2, centerY - y2);
		}
		
		public void drawTo(BufferedImage b) {
			//double projectedX1, projectedY1, projectedX2, projectedY2;
			Graphics2D g = b.createGraphics();
			g.setColor(Color.black);
			//int centerX = b.getWidth() / 2;
			//int centerY = b.getHeight() / 2;
			//xAxisTheta = Math.toRadians(30);
			//xAxisTheta = 30;
			
			List<Vertex> rotatedVertices = new ArrayList<Vertex>();
			for (Vertex v : vertices) {
				rotatedVertices.add(v.rotate(xAxisTheta, yAxisTheta, zAxisTheta));
			}
			
			double lastX, lastY;
			Vertex v = rotatedVertices.get(rotatedVertices.size() - 1);
			double[][] scaled = Part1.multiply(new double[][]{
					{v.z + 10, 0, 0},
					{0, v.z + 10, 0},
					{0, 0, v.z + 10}
				}, v.getMatrix());
			lastX = scaled[0][0];
			lastY = scaled[1][0];
			for (int i = 0; i < rotatedVertices.size(); i++) {
				v = rotatedVertices.get(i);
				double newX, newY;
				scaled = Part1.multiply(new double[][]{
					{v.z + 10, 0, 0},
					{0, v.z + 10, 0},
					{0, 0, v.z + 10}
				}, v.getMatrix());
				newX = scaled[0][0];
				newY = scaled[1][0];
				System.out.println(lastX + " " + lastY + " " + newX + " " + newY);
				drawLine(b, (int)lastX * 5, (int)lastY * 5, (int)newX * 5, (int)newY * 5);
				//drawLine(b, 0, 0, 10, 10);
				
				lastX = newX;
				lastY = newY;
			}
			
		}
	}

	void rotate(double[][] matrix, double theta) {
		
	}
	
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Part2 window = new Part2();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * Create the application.
	 */
	public Part2() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//frame.getContentPane().setLayout(new MigLayout("", "[grow]", "[grow]"));
		
		final Polygon letterL = new Polygon(-75, 70, new Vertex(0, 0), new Vertex(4, 0),
				new Vertex(4, 2), new Vertex(2, 2), new Vertex(2, 6),
				new Vertex(0, 6), new Vertex(0, 0));
		
		final Polygon letterT = new Polygon(-350, 0, new Vertex(2, 0), new Vertex(4, 0),
				new Vertex(4, 4), new Vertex(6, 4), new Vertex(6, 6), new Vertex(0, 6),
				new Vertex(0, 4), new Vertex(2, 4), new Vertex(2, 0));
		
		final Polygon letterE = new Polygon(0, 0, new Vertex(0, 0), new Vertex(5, 0),
				new Vertex(5, 1), new Vertex(2, 1), new Vertex(2, 2), new Vertex(5, 2),
				new Vertex(5, 3), new Vertex(2, 3), new Vertex(2, 4), new Vertex(5, 4),
				new Vertex(5, 5), new Vertex(0, 5), new Vertex(0, 0));
		final Polygon letterK = new Polygon(350, 0, new Vertex(0, 0), new Vertex(2, 0),
				new Vertex(2, 2), new Vertex(4, 0), new Vertex(6, 0), new Vertex(3, 3),
				new Vertex(6, 6), new Vertex(4, 6), new Vertex(2, 4), new Vertex(2, 6),
				new Vertex(0, 6), new Vertex(0, 0));
		
		

		final JPanel panel = new JPanel();
		frame.getContentPane().add(panel, BorderLayout.CENTER);
		
		JPanel panel_1 = new JPanel();
		frame.getContentPane().add(panel_1, BorderLayout.SOUTH);
		
		
		
		JButton btnDraw = new JButton("Draw");
		btnDraw.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				BufferedImage b = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
				Graphics2D g = b.createGraphics();
				g.setColor(Color.black);
				//g.drawLine(0, 0, 10, 10);
				letterL.drawTo(b);
				panel.getGraphics().drawImage(b, 0, 0, null);
			}
		});
		panel_1.add(btnDraw);
		
		JSlider slider = new JSlider(0, 120, 0);
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent arg0) {
				JSlider source = (JSlider)arg0.getSource();
				letterL.yAxisTheta = Math.toRadians(source.getValue());
				System.out.println(Math.toRadians(source.getValue()));
				BufferedImage b = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
				Graphics2D g = b.createGraphics();
				g.setBackground(Color.white);
				g.clearRect(0, 0, panel.getWidth(), panel.getHeight());
				g.setColor(Color.black);
				g.drawLine(0, b.getHeight()/2, b.getWidth(), b.getHeight()/2);
				g.drawLine(b.getWidth()/2, 0, b.getWidth()/2, b.getHeight());
				//letterL.drawTo(b);
				Animation animT = new Animation(letterT, 121, 3, Axes.Z);
				Animation animE = new Animation(letterE, 121, 2, Axes.Y);
				Animation animK = new Animation(letterK, 121, 5, Axes.X);
				
				animT.draw(b, source.getValue());
				animE.draw(b, source.getValue());
				animK.draw(b, source.getValue());
				//panel.getGraphics().clearRect(0, 0, panel.getWidth(), panel.getHeight());
				panel.getGraphics().drawImage(b, 0, 0, null);
			}
		});
		panel_1.add(slider);
	}
	
}
